/*
 * Based on arch/x86/kernel/early_printk.c
 */

#include "console.h"

#define TXR 0 /*  Transmit register (WRITE) */
#define RXR 0 /*  Receive register  (READ)  */
#define IER 1 /*  Interrupt Enable          */
#define IIR 2 /*  Interrupt ID              */
#define FCR 2 /*  FIFO control              */
#define LCR 3 /*  Line control              */
#define MCR 4 /*  Modem control             */
#define LSR 5 /*  Line Status               */
#define MSR 6 /*  Modem Status              */
#define DLL 0 /*  Divisor Latch Low         */
#define DLH 1 /*  Divisor latch High        */

#define UART_BASE 0x3f8

static void cpu_relax(void)
{
	asm volatile("rep; nop");
}

static unsigned char register_read(unsigned short reg)
{
	unsigned char v;
	reg += UART_BASE;
	asm volatile("inb %1,%0" : "=a" (v) : "dN" (reg));
	return v;
}

static void register_write(unsigned short reg, unsigned char v)
{
	reg += UART_BASE;
	asm volatile("outb %0,%1" : : "a" (v), "dN" (reg));
}

void console_init(void)
{
	unsigned char c;

	register_write(LCR, 3);
	register_write(IER, 0);
	register_write(FCR, 0);
	register_write(MCR, 3);

	c = register_read(LCR);
	register_write(LCR, c | (1 << 7));
	register_write(DLL, 1);
	register_write(DLH, 0);
	register_write(LCR, c & ~(1 << 7));
}

void console_print_char(char ch)
{
	unsigned char v;

	while (1) {
		v = register_read(LSR);
		if (v & (1 << 5))
			break;
		cpu_relax();
	}

	register_write(TXR, ch);
}

